// import com.alibaba.druid.DbType_ptr;
// import com.alibaba.druid.FastsqlException;
// import com.alibaba.druid.sql.SQLUtils;
// import com.alibaba.druid.sql.ast.SQLDataType;
// import com.alibaba.druid.sql.ast.SQLExpr_ptr;
// import com.alibaba.druid.sql.ast.SQLName_ptr;
// import com.alibaba.druid.sql.ast.SQLStatement_ptr;
// import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr;
// import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
// import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
// import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
// import com.alibaba.druid.sql.ast.statement.*;
// import com.alibaba.druid.sql.dialect.hive.stmt.HiveCreateTableStatement;
// import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
// import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement;
// import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateTableStatement;
// import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitorAdapter;
// import com.alibaba.druid.sql.parser.SQLParserFeature;
// import com.alibaba.druid.sql.repository.function.Function_ptr;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor_ptr;
// import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter;
// import com.alibaba.druid.support.logging.Log;
// import com.alibaba.druid.support.logging.LogFactory;
// import com.alibaba.druid.util.FnvHash;

// import java.io.IOException;
// import java.util.Collection;
// import java.util.LinkedHashMap;
// import java.util.List;
// import java.util.std::map;
// import java.util.concurrent.ConcurrentHashMap;
#pragma once
#include <map>
#include <unordered_map>
#include "../../utils/common_ptr.h"
#include "../dialect/mysql/visitor/MySqlASTVisitorAdapter.h"
#include "../dialect/oracle/visitor/OracleASTVisitorAdapter.h"
#include "../dialect/sqlserver/visitor/SQLServerASTVisitorAdapter.h"
#include "../visitor/SQLASTVisitorAdapter.h"

class SchemaRepository_SchemaLoader
{
public:
  string_ptr loadDDL(string_ptr catalog, string_ptr schema, string_ptr objectName){};
};

class SchemaRepository_MySqlConsoleSchemaVisitor : public MySqlASTVisitorAdapter
{
public:
  SchemaRepository *schemaRepository_;
  SchemaRepository_MySqlConsoleSchemaVisitor(SchemaRepository *schemaRepository);
  bool visit(SQLDropSequenceStatement_ptr x);

  BOOL_ptr visit(SQLCreateSequenceStatement *x);

  BOOL_ptr visit(HiveCreateTableStatement_ptr x);

  BOOL_ptr visit(MySqlCreateTableStatement_ptr x);

  bool visit(SQLCreateTableStatement_ptr x);

  bool visit(SQLDropTableStatement_ptr x);

  // BOOL_ptr visit(SQLCreateViewStatement *x);

  // BOOL_ptr visit(SQLAlterViewStatement *x);

  // BOOL_ptr visit(SQLCreateIndexStatement *x);

  // BOOL_ptr visit(SQLCreateFunctionStatement *x);

  // BOOL_ptr visit(SQLAlterTableStatement *x);

  BOOL_ptr visit(SQLUseStatement *x);

  bool visit(SQLDropIndexStatement_ptr x);
};

class SchemaRepository_OracleConsoleSchemaVisitor : public OracleASTVisitorAdapter
{
public:
  SchemaRepository *schemaRepository_;
  SchemaRepository_OracleConsoleSchemaVisitor(SchemaRepository *schemaRepository);

  bool visit(SQLDropSequenceStatement_ptr x);

  BOOL_ptr visit(SQLCreateSequenceStatement *x);

  // BOOL_ptr visit(OracleCreateTableStatement *x);

  bool visit(SQLCreateTableStatement_ptr x);

  bool visit(SQLDropTableStatement_ptr x);

  // BOOL_ptr visit(SQLCreateViewStatement *x);

  // BOOL_ptr visit(SQLAlterViewStatement *x);

  // BOOL_ptr visit(SQLCreateIndexStatement *x);

  // BOOL_ptr visit(SQLCreateFunctionStatement *x);

  // BOOL_ptr visit(SQLAlterTableStatement *x);

  BOOL_ptr visit(SQLUseStatement *x);

  bool visit(SQLDropIndexStatement_ptr x);
};

class SchemaRepository_SqlServerConsoleSchemaVisitor : public SQLServerASTVisitorAdapter
{
public:
  SchemaRepository *schemaRepository_;
  SchemaRepository_SqlServerConsoleSchemaVisitor(SchemaRepository *schemaRepository);

  SchemaRepository_SqlServerConsoleSchemaVisitor();

  bool visit(SQLDropSequenceStatement_ptr x);

  BOOL_ptr visit(SQLCreateSequenceStatement *x);

  // BOOL_ptr visit(OracleCreateTableStatement *x);

  bool visit(SQLCreateTableStatement_ptr x);

  bool visit(SQLDropTableStatement_ptr x);

  // BOOL_ptr visit(SQLCreateViewStatement *x);

  // BOOL_ptr visit(SQLAlterViewStatement *x);

  // BOOL_ptr visit(SQLCreateIndexStatement *x);

  // BOOL_ptr visit(SQLCreateFunctionStatement *x);

  // BOOL_ptr visit(SQLAlterTableStatement *x);

  BOOL_ptr visit(SQLUseStatement *x);

  bool visit(SQLDropIndexStatement_ptr x);
};

class SchemaRepository_DefaultConsoleSchemaVisitor : public SQLASTVisitorAdapter
{
public:
  SchemaRepository *schemaRepository_;
  SchemaRepository_DefaultConsoleSchemaVisitor(SchemaRepository *schemaRepository);

  bool visit(SQLDropSequenceStatement_ptr x);

  BOOL_ptr visit(SQLCreateSequenceStatement *x);

  bool visit(SQLCreateTableStatement_ptr x);

  BOOL_ptr visit(HiveCreateTableStatement_ptr x);

  bool visit(SQLDropTableStatement_ptr x);

  // BOOL_ptr visit(SQLCreateViewStatement *x);

  // BOOL_ptr visit(SQLAlterViewStatement *x);

  // BOOL_ptr visit(SQLCreateIndexStatement *x);

  // BOOL_ptr visit(SQLCreateFunctionStatement *x);

  // BOOL_ptr visit(SQLAlterTableStatement *x);

  bool visit(SQLDropIndexStatement_ptr x);
};

class SchemaRepository
{
public:
  // static Log LOG = LogFactory.getLog(SchemaRepository.class);

  Schema_ptr defaultSchema;
  DbType_ptr dbType;
  DbType_ptr schemaDbType;
  SQLASTVisitor_ptr consoleVisitor;
  std::map<std::string, Schema_ptr> schemas;
  std::map<long, repository_Function_ptr> internalFunctions;
  SchemaRepository_SchemaLoader_ptr schemaLoader;

  SchemaRepository();
  SchemaRepository(DbType_ptr dbType);

  SchemaRepository(DbType_ptr dbType, DbType_ptr schemaDbType);
  SHAREDOBJECT(SchemaRepository);
  DbType_ptr getDbType();

  string_ptr getDefaultSchemaName();

  void setDefaultSchema(string_ptr name);

  Schema_ptr findSchema(string_ptr schema);

  Schema_ptr findSchema(string_ptr name, BOOL_ptr create);

  Schema_ptr getDefaultSchema();

  void setDefaultSchema(Schema_ptr schema);

  SchemaObject_ptr findTable(string_ptr tableName);

  SchemaObject_ptr findView(string_ptr viewName);

  SchemaObject_ptr findTable(long tableNameHash);

  SchemaObject_ptr findTableOrView(string_ptr tableName);

  SchemaObject_ptr findTableOrView(string_ptr tableName, BOOL_ptr onlyCurrent);

  Schema_list_ptr getSchemas();

  SchemaObject_ptr findFunction(string_ptr functionName);

  void acceptDDL(string_ptr ddl);

  SchemaObject_ptr acceptDDL(string_ptr ddl, DbType_ptr dbType);

  void accept(SQLStatement_ptr stmt);

  BOOL_ptr isSequence(string_ptr name);

  SchemaObject_ptr findTable(SQLTableSource_ptr tableSource, string_ptr alias);

  SQLColumnDefinition_ptr findColumn(SQLTableSource_ptr tableSource, SQLSelectItem_ptr selectItem);

  SQLColumnDefinition_ptr findColumn(SQLTableSource_ptr tableSource, SQLExpr_ptr expr);

  SchemaObject_ptr findTable(SQLTableSource_ptr tableSource, SQLSelectItem_ptr selectItem);

  SchemaObject_ptr findTable(SQLTableSource_ptr tableSource, SQLExpr_ptr expr);

  std::unordered_map<std::string, SchemaObject_ptr> getTables(SQLTableSource_ptr x);

  BOOL_ptr removeTable(SQLName_ptr name);

  int getTableCount();

  SchemaObject_list_ptr getObjects();

  int getViewCount();

  void resolve(SQLSelectStatement_ptr stmt, SchemaResolveVisitor_Option_list_ptr options);

  void resolve(SQLSelect_ptr select, SchemaResolveVisitor_Option_list_ptr options);

  void resolve(SQLSelectQueryBlock_ptr queryBlock, SchemaResolveVisitor_Option_list_ptr options);

  void resolve(SQLStatement_ptr stmt, SchemaResolveVisitor_Option_list_ptr options);
  void resolve(SQLStatement_ptr stmt)
  {
    SchemaResolveVisitor_Option_list_ptr tmp = std::make_shared<std::list<SchemaResolveVisitor_Option_ptr>>();
    resolve(stmt, tmp);
  }

  SchemaResolveVisitor_ptr createResolveVisitor(SchemaResolveVisitor_Option_list_ptr options);

  string_ptr resolve(string_ptr input);

  string_ptr console(string_ptr input);

  SchemaObject_ptr findTable(SQLName_ptr name);

  SchemaObject_ptr findView(SQLName_ptr name);

  BOOL_ptr renameTable(SQLName_ptr name, SQLName_ptr to);

  SchemaObject_ptr findTable(SQLExprTableSource_ptr x);

  SchemaObject_ptr acceptCreateTable(MySqlCreateTableStatement_ptr x);

  SchemaObject_ptr acceptCreateTable(SQLCreateTableStatement_ptr x);

  BOOL_ptr acceptDropTable(SQLDropTableStatement_ptr x);

  // SchemaObject_ptr acceptView(SQLCreateViewStatement *x);

  // BOOL_ptr acceptView(SQLAlterViewStatement *x);

  BOOL_ptr acceptDropIndex(SQLDropIndexStatement_ptr x);

  // BOOL_ptr acceptCreateIndex(SQLCreateIndexStatement *x);

  // BOOL_ptr acceptCreateFunction(SQLCreateFunctionStatement *x);

  // BOOL_ptr acceptAlterTable(SQLAlterTableStatement *x);

  BOOL_ptr acceptCreateSequence(SQLCreateSequenceStatement *x);

  BOOL_ptr acceptDropSequence(SQLDropSequenceStatement_ptr x);

  SQLDataType_ptr findFuntionReturnType(long functionNameHashCode);

  string_ptr loadDDL(string_ptr table);

  string_ptr loadDDL(string_ptr schema, string_ptr table);

  string_ptr loadDDL(string_ptr catalog, string_ptr schema, string_ptr table);

  SchemaRepository_SchemaLoader_ptr getSchemaLoader();

  void setSchemaLoader(SchemaRepository_SchemaLoader_ptr schemaLoader);
};
